package rioharkka;

import java.io.*;
import java.util.*;

public class Main {

    protected static int size;
    protected static float[][] multiply1;
    protected static float[][] multiply2;
    protected static float[][] result;
    protected static int ready = 8;
    protected static long time = 0;

    private static float[][] checkResult;

    public static void main(String[] args) throws IOException {
        String file1 = args[0];
        String file2 = args[1];
        String writeFile = args[2];
        String test = args[3];
        read(file1, file2);
        int calculated = calcPerThreads();
        int calcPlus = remainder();
        int[] allCalcs = new int[8];
        if (size < 8) {
            allCalcs[0] = 1;
            for (int i = 1; i < size; i++) {
                allCalcs[i] = 1 + allCalcs[i-1];
            }
        }
        else {
            allCalcs[0] = calculated;
            for (int i = 1; i < 8; i++) {
                allCalcs[i] = calculated + allCalcs[i-1];
                if (i <= calcPlus) {
                    allCalcs[i] += 1;
                }
            }
        }

        Runnable r1 = new MyRunnable(0, allCalcs[0]);
        Thread t1 = new Thread(r1);
       
        Runnable r2 = new MyRunnable(allCalcs[0], allCalcs[1]);
        Thread t2 = new Thread(r2);

        Runnable r3 = new MyRunnable(allCalcs[1], allCalcs[2]);
        Thread t3 = new Thread(r3);

        Runnable r4 = new MyRunnable(allCalcs[2], allCalcs[3]);
        Thread t4 = new Thread(r4);

        Runnable r5 = new MyRunnable(allCalcs[3], allCalcs[4]);
        Thread t5 = new Thread(r5);

        Runnable r6 = new MyRunnable(allCalcs[4], allCalcs[5]);
        Thread t6 = new Thread(r6);

        Runnable r7 = new MyRunnable(allCalcs[5], allCalcs[6]);
        Thread t7 = new Thread(r7);

        Runnable r8 = new MyRunnable(allCalcs[6], allCalcs[7]);
        Thread t8 = new Thread(r8);

        System.out.println("Lasketaan...");

        long startTime = System.currentTimeMillis();

        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
        t6.start();
        t7.start();
        t8.start();

        while (ready > 0 ) {
            System.out.print("");
        }

        long stopTime = System.currentTimeMillis();
        time = (stopTime - startTime);

        System.out.println("\nSuoritusaika: " + time + " millisekuntia.");

        System.out.println("Kirjoitetaan tulosmatriisi tiedostoon " + writeFile);
        write(writeFile);

        if (test.contains("test")) {
            System.out.println("Käynnistetään tarkistuslaskenta.");
            checkResult = new float[size][size];
            calculate(0, size-1);
            if (check() == true) System.out.println("Laskenta suoritettu oikein.");
            else System.out.println("Laskennassa on virhe!");
        }
    }

    /* Funktio lukee tiedoston, jossa on ensin kokonaisluku n, joka kertoo
     * matriisien koon (n x n). Muun kokoisia matriiseja ei siis tule!
     * (Voidaanko tämä olettaa, vai pitäisikö silti tarkistaa? Syötteiden
     * lukemista, tarkistamista yms ei tarvitse huomioida suoritusajan
     * laskemisessa.) Lisäksi luetaan matriisit, jotka on esitetty välimerkillä
     * erotettuina float-lukuina yhdellä ainoalla rivillä.
     *
     */
    public static void read(String file1, String file2) throws IOException {
        Scanner reading1 = new Scanner(new File (file1)).useLocale(new Locale("en_GB"));  //tämän voisi ottaa komentoriviparametrina
        Scanner reading2 = new Scanner(new File (file2)).useLocale(new Locale("en_GB"));
        size = reading1.nextInt();
        reading2.nextInt();

        multiply1 = new float[size][size];
        multiply2 = new float[size][size];
        result = new float[size][size];

        System.out.println("Luetaan tiedosto " + file1);
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                multiply1[i][j] = reading1.nextFloat();
            }
        }
        System.out.println("Luetaan tiedosto " + file2);
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                multiply2[i][j] = reading2.nextFloat();
            }
        }
        reading1.close();
        reading2.close();
    }

    /* Lasketaan, kuinka monta laskentayksikköä (row * columnit) tulee per
     * threadi. Ja...
     */
    public static int calcPerThreads() {
        if (size < 8 ) return 0;
        else return size / 8;
    }

    /* ...jotta homma menee tasan, jakojäännöksen verran threadeja saa yhden
     * ylimääräisen laskentayksikön. Näiden lukumäärän saa tällä funktiolla.
     */
    public static int remainder() {
        if (size < 8) return 0;
        else return size % 8;
    }

    /* Funktio, joka laskee tulosmatriisin lineaarisesti.
     */
    public static void calculate(int firstRow, int lastRow) {
        for (int i = firstRow; i <= lastRow; i++) {
            for (int j = 0; j < size; j++) {
                float temp = 0;
                for (int k = 0; k < size; k++) {
                    temp += multiply1[i][k] * multiply2[k][j];
                }
                checkResult[i][j] = temp;
            }
        }
    }


    // Kirjoittaa tulosmatriisin tiedostoon
    public static void write(String writeFile) throws IOException {
        File printFile = new File(writeFile);
        printFile.createNewFile();
        PrintWriter printing = new PrintWriter(printFile);

        printing.print(size + "   ");  // kirjoitetaan tiedoston koko

        //Kirjoitetaan varsinainen matriisi.
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                printing.print(result[i][j] + " ");
            }
        }

        printing.close();
    }

    // Tarkistaa ovaatko kaksi tulosmatriisia samat.
    public static boolean check() {
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                if (result[i][j] != checkResult[i][j]) return false;
            }
        }
        return true;
    }

}
